package com.gxa.mobile.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.github.benmanes.caffeine.cache.Cache;
import com.gxa.service.GoodsRpcVo;
import com.gxa.mobile.service.ShoppingCarService;
import com.gxa.service.OrderListRpcDto;

import com.gxa.Vo.OrderlistRpcVo;

import com.gxa.core.result.MessageCode;
import com.gxa.mobile.exception.CustomException;
import com.gxa.mobile.service.OrderListService;
import com.gxa.mobile.utils.UserThreadLocal;
import com.gxa.service.OrderListRpcService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author：lizhijun
 * @Package：{PROJECT_NAME}
 * @name：{DATE} {NAME}
 */
@Slf4j
@Service
public class OrderListServiceImpl implements OrderListService {
    //订单本地缓存前缀
    public static final String ORDER_CACHE = "order_cache:";

    //dubbo远程调用
    @Reference
    private OrderListRpcService orderListRpcService;

    private ShoppingCarService shoppingCarService;
    //订单缓存对象
    @Autowired
    @Qualifier("order")
    private Cache<String, List<OrderlistRpcVo>> orderCache;

    //redis
    @Autowired
    private RedisTemplate redisTemplate;

    //redisson分布式锁
    @Autowired
    RedissonClient redisson;


    //根据订单id查询订单详情
    @Override
    public OrderlistRpcVo getOrderList(String orderId) {
        Integer userId = UserThreadLocal.getUser().getUserId();
        // 1. 先从本地缓存查询订单详情
//        List<OrderlistRpcVo> orderlistRpcVo = this.orderCache.getIfPresent(ORDER_CACHE + userId);
//        if (orderlistRpcVo != null) {
//            for (OrderlistRpcVo order : orderlistRpcVo) {
//                if (order.getOrderId().equals(orderId)) {
//                    log.info("订单详情从本地缓存中查询");
//                    return order;
//                }
//            }
//        }
        // 2. 从Redis查询订单详情
        RLock lock = redisson.getLock(userId + "");
        try {
            lock.lock();

            // 从Redis获取订单详情
            Map<String, OrderlistRpcVo> userOrders = redisTemplate.opsForHash().entries(ORDER_CACHE + userId);
            if (userOrders != null && !userOrders.isEmpty()) {
                log.info("用户订单从Redis中查询{}", userOrders);
                // 直接从Redis中获取指定订单ID的订单详情
                OrderlistRpcVo targetOrder = userOrders.get(orderId);
                if (targetOrder != null) {
                    //放入本地缓存
                    //  this.orderCache.put(ORDER_CACHE + userId, Collections.singletonList(targetOrder));
                    return targetOrder;
                }
            }
            // 3. 从MySQL查询订单详情
            OrderlistRpcVo orderList = this.orderListRpcService.getOrderList(orderId);
            log.info("订单详情从MySQL中查询");
            if (orderList == null) {
                // 把不存在的订单保存到Redis中，防止缓存穿透
                OrderlistRpcVo noOrder = new OrderlistRpcVo();
                noOrder.setOrderId(orderId);
                noOrder.setOrderType("不存在的订单");
                noOrder.setOrderDesc("不存在的订单");
                redisTemplate.opsForHash().put(ORDER_CACHE + userId, noOrder.getOrderId(), noOrder);
                throw new CustomException(MessageCode.NO_ORDER);
            }

            // 将查询到的订单详情存入Redis
            redisTemplate.opsForHash().put(ORDER_CACHE + userId, orderList.getOrderId(), orderList);

            // 将查询到的订单详情存入本地缓存
//            this.orderCache.put(ORDER_CACHE + userId, Collections.singletonList(orderList));

            return orderList;
        } finally {
            lock.unlock();
        }
    }

    //根据用户id和订单类型查询订单
    @Override
    public List<OrderlistRpcVo> findAllOrderList(String orderType) {
        Integer userId = UserThreadLocal.getUser().getUserId();

        if (userId == null) {
            throw new CustomException(MessageCode.NO_LOGIN);
        }

        // 如果orderType为空，查询所有类型的订单
        if (StringUtils.isEmpty(orderType)) {
            log.info("查询用户{}的所有订单", userId);

            // 直接从本地缓存查询订单，无需过滤
//            List<OrderlistRpcVo> orderlistRpcVo = this.orderCache.getIfPresent(ORDER_CACHE + userId);
//            if (orderlistRpcVo != null && !orderlistRpcVo.isEmpty()) {
//                log.info("用户订单从本地缓存中查询");
//                return orderlistRpcVo;
//            }

            RLock lock = redisson.getLock(userId + "");
            try {
                lock.lock();

                // 从Redis查询订单
                Map<String, OrderlistRpcVo> userOrders = redisTemplate.opsForHash().entries(ORDER_CACHE + userId);
                if (userOrders != null && !userOrders.isEmpty()) {
                    log.info("用户订单从Redis中查询");
                    log.info("orders-----------{}", userOrders.values());
                    // 把redis中的订单存入本地缓存
                    // this.orderCache.put(ORDER_CACHE + userId, new ArrayList<>(userOrders.values()));
                    return new ArrayList<>(userOrders.values());
                }

                // 从MySQL查询订单
                List<OrderlistRpcVo> orderList = this.orderListRpcService.findOrderList(userId, null);
                log.info("mysql查询订单{}", orderList.toString());

                if (orderList == null || orderList.isEmpty()) {
                    // 把不存在的订单保存到Redis中，防止缓存穿透
                    OrderlistRpcVo noOrder = new OrderlistRpcVo();
                    noOrder.setUserId(userId);
                    noOrder.setOrderType("不存在");
                    noOrder.setStatus("不存在");
                    redisTemplate.opsForHash().put(ORDER_CACHE + userId, "no_order", noOrder);
                    throw new CustomException(MessageCode.NO_ORDER);
                }

                log.info("用户订单从MySQL中查询");
                Map<String, OrderlistRpcVo> ordersMap = new HashMap<>();
                for (OrderlistRpcVo order : orderList) {
                    ordersMap.put(order.getOrderId(), order);
                }
                redisTemplate.opsForHash().putAll(ORDER_CACHE + userId, ordersMap);

                // 将查询到的订单存入本地缓存
                //  this.orderCache.put(ORDER_CACHE + userId, orderList);

                return orderList;
            } finally {
                lock.unlock();
            }
        } else {
            // 如果orderType不为空，按类型过滤订单
            return findFilteredOrdersByType(userId, orderType);
        }
    }

    private List<OrderlistRpcVo> findFilteredOrdersByType(Integer userId, String orderType) {
        //List<OrderlistRpcVo> cachedOrders = this.orderCache.getIfPresent(ORDER_CACHE + userId);
//        if (cachedOrders != null && !cachedOrders.isEmpty()) {
//            log.info("用户订单从本地缓存中查询");
//            return filterOrdersByType(cachedOrders, orderType);
//        }

        RLock lock = redisson.getLock(userId + "");
        try {
            lock.lock();

            // 从Redis查询订单
            Map<String, OrderlistRpcVo> userOrders = redisTemplate.opsForHash().entries(ORDER_CACHE + userId);
            if (userOrders != null && !userOrders.isEmpty()) {
                log.info("用户订单从Redis中查询");
                log.info("orders-----------{}", userOrders.values());
                // 把redis中的订单存入本地缓存
                // this.orderCache.put(ORDER_CACHE + userId, new ArrayList<>(userOrders.values()));
                return filterOrdersByType(new ArrayList<>(userOrders.values()), orderType);
            }

            // 从MySQL查询订单
            List<OrderlistRpcVo> orderList = this.orderListRpcService.findOrderList(userId, orderType);
            log.info("mysql查询订单{}", orderList.toString());

            if (orderList == null || orderList.isEmpty()) {
                // 把不存在的订单保存到Redis中，防止缓存穿透
                OrderlistRpcVo noOrder = new OrderlistRpcVo();
                noOrder.setUserId(userId);
                noOrder.setOrderType("不存在");
                noOrder.setStatus("不存在");
                redisTemplate.opsForHash().put(ORDER_CACHE + userId, "no_order", noOrder);
                throw new CustomException(MessageCode.NO_ORDER);
            }

            log.info("用户订单从MySQL中查询");
            Map<String, OrderlistRpcVo> ordersMap = new HashMap<>();
            for (OrderlistRpcVo order : orderList) {
                ordersMap.put(order.getOrderId(), order);
            }
            redisTemplate.opsForHash().putAll(ORDER_CACHE + userId, ordersMap);

            // 将查询到的订单存入本地缓存
            //this.orderCache.put(ORDER_CACHE + userId, orderList);

            return orderList;
        } finally {
            lock.unlock();
        }
    }

    //这是订单状态过滤器
    private List<OrderlistRpcVo> filterOrdersByType(List<OrderlistRpcVo> orders, String orderType) {
        return orders.stream()
                .filter(Objects::nonNull) // 过滤掉null值
                .filter(order -> order.getOrderType().equals(orderType))
                .collect(Collectors.toList());
    }

    //这是缓存预热中，直接远程调用查询所有订单，放入redis
    @Override
    public List<OrderlistRpcVo> findAllOrderList() {
        List<OrderlistRpcVo> orderList = orderListRpcService.findOrderList();
        return orderList;
    }

    // 这是订单创建订单的方法，将购物车的数据和用户数据和订单页面数据创建一个未支付订单对象
    @Override
    public OrderListRpcDto createOrderListRpcDto(GoodsRpcVo goodsRpcVo) {
        //需要获取购物车里面的商品id，商品数量，商品价格
        //创建一个订单对像，将购物车里面的商品id，商品数量，商品价格，放入订单对象
        OrderListRpcDto orderListRpcDto = new OrderListRpcDto();
        orderListRpcDto.setGoodsId(goodsRpcVo.getGoodsId());
        orderListRpcDto.setCount(goodsRpcVo.getCount());
        orderListRpcDto.setOrderPrice(goodsRpcVo.getTotalPrice());
        return orderListRpcDto;
    }

    //添加订单，这是点击结算按钮过后，将订单加入数据库，订单状态为未支付
    @Override
    public int addOrderList(OrderListRpcDto orderListRpcDto) {
        Integer userId = UserThreadLocal.getUser().getUserId();

        //获取订单中的商品信息
        orderListRpcDto.setUserId(userId);
        orderListRpcDto.setStatus("未支付");
        return this.orderListRpcService.addOrderList(orderListRpcDto);
    }

    //更改订单状态
    @Override
    public int updateOrder(OrderListRpcDto orderListRpcDto) {

        return this.orderListRpcService.updateOrder(orderListRpcDto);
    }


}
